#ifndef PARSE_STATEMENT__
#define PARSE_STATEMENT__

#include <assert.h>
#include <stdlib.h>
#include "parse-basic.h"
#include "parse-declaration.h"
#include "parse-expression.h"
#include "parse-type.h"
#include "token.h"
#include "../ast/statement.h"

#if 0
import std.assert;
import std.lib;
import parse-basic;
import parse-declaration;
import parse-expression;
import parse-type;
import token;
import ..ast.statement;
#endif

struct Statement* parseStatement(struct TokenList**);
struct StatementList* parseStatementList(struct TokenList**);

struct Statement* parseAssignmentStatement(struct TokenList** source)
{
	struct TokenList* save = *source;
	struct AssignmentStatement* r = malloc(sizeof(struct AssignmentStatement));
	// TODO
	free(r);
	*source = save;
	return NULL;
}

struct Statement* parseBlockStatement(struct TokenList** source)
{
	struct TokenList* save = *source;
	struct BlockStatement* r = malloc(sizeof(struct BlockStatement));

	if((*source)->head->tag == OPEN_PARENTHESE)
	{
		*source = (*source)->tail;
		r->list = parseStatementList(source);

		if((*source)->head->tag == CLOSE_PARENTHESE)
		{
			*source = (*source)->tail;
			return allocateStatement(BLOCK_STATEMENT,r);
		}
	}

	free(r);
	*source = save;
	return NULL;
}

struct Statement* parseExpressionStatement(struct TokenList** source)
{
	struct TokenList* save = *source;
	struct ExpressionStatement* r = malloc(sizeof(struct ExpressionStatement));
	// TODO
	assert(0); // Not implemented.
	free(r);
	*source = save;
	return NULL;
}

struct Statement* parseEnumDeclarationStatement(
	struct TokenList** source)
{
	// TODO
	assert(0); // Not implemented
	return NULL;
}

struct Statement* parseFlowStatement(struct TokenList** source)
{
	struct TokenList* save = *source;
	enum FlowStatement* r = malloc(sizeof(enum FlowStatement));
	// TODO
	assert(0); // Not yet implemented.
	free(r);
	*source = save;
	return NULL;
}

struct Statement* parseFunctionDeclarationStatement(
	struct TokenList** source)
{
	// TODO
	assert(0); // Not yet implemented.
	return NULL;
}

struct Statement* parseIfStatement(struct TokenList** source)
{
	struct TokenList* save = *source;
	struct IfStatement* r = malloc(sizeof(struct IfStatement));
	// TODO
	assert(0); // Note yet implemented.
	free(r);
	*source = save;
	return NULL;
}

struct Statement* parseLabelStatement(struct TokenList** source)
{
	struct TokenList* save = *source;
	struct Name* name = parseName(source);

	if(name != NULL && (*source)->head->tag == COLON)
	{
		*source = (*source)->tail;

		struct Statement* statement = parseStatement(source);

		if(statement != NULL)
			return allocateStatement(LABEL_STATEMENT,
				allocateLabelStatement(name,statement));
	}

	freeName(name);
	*source = save;
	return NULL;
}

struct Statement* parsePostfixStatement(struct TokenList** source)
{
	struct TokenList* save = *source;
	struct PostfixStatement* r = malloc(sizeof(struct PostfixStatement));
	// TODO
	assert(0); // Not yet implemented.
	free(r);
	*source = save;
	return NULL;
}

struct Statement* parseReturnStatement(struct TokenList** source)
{
	struct TokenList* save = *source;
	struct ReturnStatement* r = malloc(sizeof(struct ReturnStatement));

	if((*source)->head->tag == KEYWORD_RETURN_TOKEN)
	{
		*source = (*source)->tail;
		r->type = parseType(source); // can be NULL
		r->expression = parseExpression(source); // can be NULL

		if((*source)->head->tag == SEMICOLON)
		{
			*source = (*source)->tail;
			return allocateStatement(RETURN_STATEMENT,r);
		}
	}

	free(r);
	*source = save;
	return NULL;
}

struct Statement* parseStructDeclarationStatement(
	struct TokenList** source)
{
	// TODO
	assert(0); // Not yet implemented.
	return NULL;
}

struct Statement* parseUnionDeclarationStatement(
	struct TokenList** source)
{
	// TODO
	assert(0); // Not yet implemented.
	return NULL;
}

struct Statement* parseVariableDeclarationStatement(
	struct TokenList** source)
{
	// TODO
	assert(0); // Not yet implemented.
	return NULL;
}

struct Statement* parseWhileStatement(struct TokenList** source)
{
	struct TokenList* save = *source;
	struct WhileStatement* r = malloc(sizeof(struct WhileStatement));
	// TODO
	assert(0); // Not yet implemented.
	free(r);
	*source = save;
	return NULL;
}

struct Statement* parseStatement(struct TokenList** source)
{
	if(*source == NULL) return NULL;

	if((*source)->head->tag == SEMICOLON)
	{
		*source = (*source)->tail;
		return allocateStatement(EMPTY_STATEMENT,NULL);
	}

	struct Statement* statement = NULL;

	struct Statement* ((*parser[2])(struct TokenList**)) =
	{
		// TODO parseAssignmentStatement,
		parseBlockStatement,
		// TODO parseEnumDeclarationStatement,
		// TODO parseExpressionStatement,
		// TODO parseFlowStatement,
		// TODO parseFunctionDeclarationStatement,
		// TODO parseIfStatement,
		// TODO parseLabelStatement,
		// TODO parsePostfixStatement,
		parseReturnStatement//,
		// TODO parseStructDeclarationStatement,
		// TODO parseUnionDeclarationStatement,
		// TODO parseVariableDeclarationStatement,
		// TODO parseWhileStatement
	};

	int i = 0;
	for(i = 0; i < 2; i++)
		if((statement = (parser[i])(source)))
			return statement;

	return NULL;
}

struct StatementList* parseStatementList(struct TokenList** source)
{
	struct Statement* statement = parseStatement(source);

	if(statement != NULL)
		return allocateStatementList(statement,parseStatementList(source));

	return NULL;
}

#endif
